﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Controls;

namespace MyModeler
{
    public enum SelectMode
    {
        none,
        //netSelect,
        move,
        size
    };

    public enum ElementType
    {
        type_unknown, type_select, type_shapes_simple, type_image, type_shapes_infrastructure, type_text, type_shapes_development
    };

    public enum ShapeType : int 
    {
	    // Simple
	    line = 0,
	    line_right,
	    rectangle,
	    ellipse,
	    rectangle_round,
	    triangle,
	    line_broken,
	    line_broken_right,
	    notimp_igloo,
	    notimpl_multi_line,
	    arrow_right,
	    arrow_down,
	    notimpl_courbe1,
	    notimpl_courbe2,
	    parenthese_gauche,
	    parenthese_droite,
	    etoile,
	    line2 = 18,
	    line_right2,
	    line_left_right,
	    // Image
	    image_fixed = 50,
	    image_scaled,
	    // Infrastructure
	    infrastructure_server_ad = 100,
	    infrastructure_server,
	    infrastructure_server_web,
	    infrastructure_server_database,
	    infrastructure_workstation,
	    infrastructure_laptop,
	    infrastructure_firewall,
	    infrastructure_network,
	    infrastructure_virtual_server,
	    infrastructure_virtual_server_web,
	    infrastructure_virtual_server_database,
	    infrastructure_virtualization_server,
	    infrastructure_server_ad_grey,
	    infrastructure_server_grey,
	    infrastructure_server_database_grey,
	    infrastructure_server_farm,
	    infrastructure_workstation_grey,
	    infrastructure_laptop_grey,
	    // Text
	    text = 200,
	    text_left,
	    text_center,
	    text_right,
	    text_justify,
	    // Development
	    development_class = 300,
	    development_interface,
	    development_enumeration,
	    development_package,
	    development_comment,
	    development_component,
	    development_association,
	    development_aggregation,
	    development_composition,
	    development_dependency,
	    development_inheritance,
	    development_package_import,
	    development_connector,
	    unknown = 1000
    };

    public enum TrackerState { normal, selected, active };

    public class CElement
    {
        public CElement()
        {
            m_objectId = Guid.NewGuid().ToString();
            m_rect = new Rect(0, 0, 0, 0);
            m_point = new Point(0, 0);
            m_text = String.Empty;
            m_bColorFill = true;
            m_colorFill = Colors.Azure;
            m_bColorLine = true;
            m_colorLine = Colors.White;
            m_last = m_point;
            m_type = ElementType.type_unknown;
	        m_shapeType = ShapeType.unknown;
        }

	    public string m_name;
	    public ElementType m_type;
	    public ShapeType m_shapeType;
	    public string m_objectId;
        public string m_caption;
        public string m_text;
	    public Rect m_rect;
	    public Point m_point;
	    public Point m_last;
	    public Color m_colorFill;
	    public bool m_bColorFill;
	    public Color m_colorLine;
	    public bool m_bSolidColorFill;
	    public bool m_bColorLine;
	    public int m_lineWidth;
	    public bool m_bLineWidth;
        public string m_image;
	    // Handling Moving stuff
	    public bool m_bMoving;
	    // Connectivity
        //CElementManager * m_pManager;
        //CModeler1View * m_pView;

        public override String ToString()
        {
            String str;
            str = String.Format("Element name=<{0}> id={1} type=<{2}> caption=<{3}> text=<{4}> image=<{5}> colorFill={6} colorLine={7} rect={8},{9},{10},{11}", 
                m_name, m_objectId, m_type, m_caption, m_text, m_image,
                m_colorFill, m_colorLine, 
                m_rect.Left, m_rect.Top, m_rect.Right, m_rect.Bottom);
            return str;
        }

        public void Draw(Windows.UI.Xaml.Controls.Canvas canvas1)
        {
            double width = m_rect.Width; //100;
            double height = m_rect.Height; //100;
            double x = m_rect.Left; // m_point.X;
            double y = m_rect.Top; // m_point.Y;

            Color color1 = Colors.LightBlue;
            Color color2 = Colors.DarkSlateBlue;
            LinearGradientBrush lgBrush = new LinearGradientBrush();
            lgBrush.StartPoint = new Point(0.5, 0);
            lgBrush.EndPoint = new Point(0.5, 1);
            GradientStop s1 = new GradientStop();
            s1.Color = color1;
            s1.Offset = 0;
            GradientStop s2 = new GradientStop();
            s2.Color = color2;
            s2.Offset = 1;
            lgBrush.GradientStops.Add(s1);
            lgBrush.GradientStops.Add(s2);

            SolidColorBrush sBrush = new SolidColorBrush(Colors.White); //.DarkBlue);

            if (m_shapeType == ShapeType.rectangle)
            {
                Rectangle r = new Rectangle();
                Thickness tn = new Thickness(x, y, 0, 0);
                r.Margin = tn;
                r.Width = width;
                r.Height = height;
                r.Stroke = sBrush;
                r.Fill = lgBrush;
                r.StrokeThickness = 2;
                canvas1.Children.Add(r);
            }

            if (m_shapeType == ShapeType.ellipse)
            {
                Ellipse el = new Ellipse();
                Thickness tn = new Thickness(x, y, 0, 0);
                el.Margin = tn;
                el.Width = width;
                el.Height = height;
                el.Stroke = new SolidColorBrush(Colors.White); //DarkBlue);
                el.StrokeThickness = 2;
                el.Fill = lgBrush;
                canvas1.Children.Add(el);
            }

            if (m_shapeType == ShapeType.line)
            {
                Line el = new Line();
                el.X1 = x;
                el.X2 = x + width;
                el.Y1 = y;
                el.Y2 = y + height;
                el.Stroke = new SolidColorBrush(Colors.DarkBlue);
                el.StrokeThickness = 2;
                canvas1.Children.Add(el);
            }

            if (m_shapeType == ShapeType.text)
            {
                TextBlock t = new TextBlock();
                //TextBox t = new TextBox();
                Thickness tn = new Thickness(x, y, 0, 0);
                t.Text = m_text; // "xxxxxxxxx xxx xxx";
                t.Margin = tn;
                canvas1.Children.Add(t);
                
            }

            //DrawSizingRect(canvas1);
        }

        private void DrawSizingRect(Windows.UI.Xaml.Controls.Canvas canvas1)
        {
            double width = m_rect.Width;
            double height = m_rect.Height;
            double x = m_rect.Left;
            double y = m_rect.Top;
            double stepX = width / 10;
            double stepY = height / 10;

            SolidColorBrush sBrush = new SolidColorBrush(Colors.Yellow);

            Rectangle r = new Rectangle();
            Thickness tn = new Thickness(x + width - stepX, y + height - stepY, 0, 0);
            r.Margin = tn;
            r.Width = stepX;
            r.Height = stepY;
            r.Stroke = sBrush;
            r.StrokeThickness = 1;
            canvas1.Children.Add(r);
        }

        internal void InvalidateObj()
        {
            //this->m_rect.SetRect(this->m_point, this->m_last);
            m_rect = new Rect(m_point, m_last);         
            //m_rect.Width = 100;
            //m_rect.Height = 100;

	        //if( m_shapeType == ShapeType::line )
	        //FIX ME: Add IsLine()
	        if( m_shapeType == ShapeType.line ||  m_shapeType == ShapeType.line2 ||
		        m_shapeType == ShapeType.line_left_right ||
		        m_shapeType == ShapeType.line_broken ||  m_shapeType == ShapeType.line_broken_right ||
		        m_shapeType == ShapeType.line_right || m_shapeType == ShapeType.line_right2 )
	        {
	        }
	        else
	        {
		        // rectangle
                //this->m_rect.NormalizeRect();
                NormalizeRect();
	        }

        }

        private void NormalizeRect()
        {
            double left = m_rect.Left;
            double top = m_rect.Top;
            double right = m_rect.Right;
            double bottom = m_rect.Bottom;
            double height = m_rect.Height;
            double witdh = m_rect.Width;

            Point p1;
            Point p2;
            p1.X = m_rect.Left;
            p1.Y = m_rect.Top;
            p2.X = m_rect.Right;
            p2.Y = m_rect.Bottom;

            if (m_rect.Left > m_rect.Right)
	        {
                p1.X = m_rect.Right;
                p2.X = m_rect.Left;
	        }

            if (m_rect.Top > m_rect.Bottom)
	        {
                p1.Y = m_rect.Bottom;
                p2.Y = m_rect.Top;
	        }

            m_rect = new Rect(p1, p2);
        }

        internal void CheckForKeepingAMinimumSize()
        {
            const int defaultSize = 10;

            // For all types
            if (m_type == ElementType.type_shapes_simple || m_type == ElementType.type_image) //m_type == type_shapes_infrastructure ) //||  )
            {
                if (m_rect.Width < defaultSize && m_rect.Height < defaultSize)
                {
                    Point p1;
                    p1.X = m_rect.Left;
                    p1.Y = m_rect.Top;
                    Point p2;
                    p2.X = p1.X + defaultSize;
                    p2.Y = p1.Y + defaultSize;
                    m_rect = new Rect(p1, p2);
                    //m_rect.SetRect(p1, p2);
                }
            }
        }

        internal void DrawTracker(Windows.UI.Xaml.Controls.Canvas canvas1, TrackerState trackerState)
        {
	        Color colorYellow = Colors.Yellow;
	        SolidColorBrush solidBrush = new SolidColorBrush(colorYellow);
	        Rect rect = m_rect;

            switch (trackerState)
	        {
	        case TrackerState.normal:
		        break;

            case TrackerState.selected:
            case TrackerState.active:
		        {
			        int nHandleCount = GetHandleCount();
			        for (int nHandle = 1; nHandle <= nHandleCount; nHandle += 1)
			        {
                        if (nHandle != 5)
                            continue;

				        Point point = GetHandle(nHandle);
                        
                        Rectangle r = new Rectangle();
                        Thickness tn = new Thickness(point.X - 3, point.Y - 3, 0, 0);
                        r.Margin = tn;
                        r.Width = 7;
                        r.Height = 7;
                        r.Fill = nHandle == 5 ? solidBrush : new SolidColorBrush(Colors.Black);
                        r.StrokeThickness = 1;
                        canvas1.Children.Add(r);
                    }
		        }
		        break;
	        }
        }

        public int HitTest(Point point)
        {
	        string str;
		    int nHandleCount = GetHandleCount();
		    for (int nHandle = 1; nHandle <= nHandleCount; nHandle += 1)
		    {
			    // GetHandleRect returns in logical coords
			    Rect rc = GetHandleRect(nHandle);

                //CRect rect(point, CSize(1, 1));
                //CRect fixed = rc;
                //CSize addSize(5,5);
                //fixed.InflateRect(addSize);
                //fixed.NormalizeRect();
                //if( (rect & fixed).IsRectEmpty() == FALSE )
			    if( PointInRect(point, rc) )
			    {
				    return nHandle;
			    }
		
		    }
	        return 0;
        }

        private Rect GetHandleRect(int nHandleID)
        {
	        Point point = GetHandle(nHandleID);
            Point p1 = new Point(point.X - 3, point.Y - 3);
            Point p2 = new Point(point.X + 3, point.Y + 3);
            return new Rect(p1, p2);
        }

        private Point GetHandle(int nHandle)
        {
            double x = 0;
            double y = 0;
            double xCenter;
            double yCenter;
            Rect rect = m_rect;

            // this gets the center regardless of left/right and top/bottom ordering
            xCenter = rect.Left + rect.Width / 2;
            yCenter = rect.Top + rect.Height / 2;

            switch (nHandle)
            {
                //default:
                //    ASSERT(FALSE);

                case 1:
                    x = rect.Left;
                    y = rect.Top;
                    break;

                case 2:
                    x = xCenter;
                    y = rect.Top;
                    break;

                case 3:
                    x = rect.Right;
                    y = rect.Top;
                    break;

                case 4:
                    x = rect.Right;
                    y = yCenter;
                    break;

                case 5:
                    x = rect.Right;
                    y = rect.Bottom;
                    break;

                case 6:
                    x = xCenter;
                    y = rect.Bottom;
                    break;

                case 7:
                    x = rect.Left;
                    y = rect.Bottom;
                    break;

                case 8:
                    x = rect.Left;
                    y = yCenter;
                    break;
            }

            return new Point(x, y);
        }

        private int GetHandleCount()
        {
	        if( m_type == ElementType.type_shapes_simple )
	        {
		        if( m_shapeType == ShapeType.line ||  m_shapeType == ShapeType.line2 ||
			        m_shapeType == ShapeType.line_left_right ||
			        m_shapeType == ShapeType.line_broken ||  m_shapeType == ShapeType.line_broken_right ||
			        m_shapeType == ShapeType.line_right || m_shapeType == ShapeType.line_right2 )
		        {
			        return 8;
			        //return 5; // should be 2
		        }
	        }
	
	        return 8;
        }

        private bool PointInRect(Point point, Rect r)
        {
            if (r.Left <= point.X && point.X <= r.Right && r.Top <= point.Y && point.Y <= r.Bottom)
            {
                return true;
            }
            else
                return false;
        }

    }
}
